import * as THREE from "three";
// 导入控制器，轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer.js";
// 导入模型解析器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { TweenMaxTo } from "./three/libs/TweenMaxTo.js";


import emitter from '../mitt/index.js';
import { ThreeSceneEvent } from '../mitt/eventType';

class Base3D {
    constructor(sceneDom, tagDom, onFinish) {
        this.container = sceneDom;
        this.tagDom = tagDom;
        this.tag = null;
        this.tagData = {
            name: ""
        };

        this.camera;
        this.scene;
        this.renderer;
        this.labelRenderer;
        this.clock = new THREE.Clock();
        this.onFinish = onFinish;
        this.progressFn;

        this.RaysMesh = [];// 防止穿透拾取到地球对面的国家

        this.hots = [];
        this.chooseMesh = null;


        this.modelUrl = "./models/school2.glb";


        this.d_skyCube = null;
        this.n_skyCube = null;
        this.lightGroup = new THREE.Group();
        this.AmbientLight = null;

        this.init();
        this.animate();
    }

    onProgress(fn) {
        this.progressFn = fn;
    }

    init() {


        //   初始化场景
        this.initScene();

        // 初始化灯光
        this.initLight();

        // 初始化渲染器
        this.initRenderer();

        // 初始化相机
        this.initCamera();

        // 控制器
        this.initControls();

        // 添加mesh
        this.addMesh();
        this.createHot();
        // 标签render
        this.inittag();
        this.iniLabelRenderer();

        // 监听场景大小改变，调整渲染尺寸
        window.addEventListener("resize", this.onWindowResize.bind(this));
        this.container.addEventListener('click', this.chooseClick.bind(this));

        this.container.addEventListener('mousemove', this.chooseMove.bind(this));


        var axesHelper = new THREE.AxesHelper(250);
        // this.scene.add(axesHelper);

    }

    initScene() {



        this.scene = new THREE.Scene();

        const d_r = "./skyboxsun25deg/";
        const n_r = "./MilkyWay/";

        const d_urls = [
            d_r + "px.jpg", d_r + "nx.jpg",
            d_r + "py.jpg", d_r + "ny.jpg",
            d_r + "pz.jpg", d_r + "nz.jpg"
        ];

        const n_urls = [
            n_r + "px.jpg", n_r + "nx.jpg",
            n_r + "py.jpg", n_r + "ny.jpg",
            n_r + "pz.jpg", n_r + "nz.jpg"
        ];

        const d_textureCube = new THREE.CubeTextureLoader().load(d_urls);
        d_textureCube.mapping = THREE.CubeRefractionMapping;
        const n_textureCube = new THREE.CubeTextureLoader().load(n_urls);
        n_textureCube.mapping = THREE.CubeRefractionMapping;

        // const d_material = new THREE.MeshBasicMaterial( { 
        //     color: 0xffffff, 
        //     side:THREE.DoubleSide , 
        //     envMap: d_textureCube ,
        //     // depthTest:false , 
        //     depthWrite : false,
        //     transparent:true,
        //     opacity:1,
        // } );
        const n_material = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            side: THREE.DoubleSide,
            envMap: n_textureCube,
            // depthTest:false , 
            depthWrite: false,
            transparent: true,
            opacity: 0,
        });
        const geometry = new THREE.BoxBufferGeometry(2200, 2200, 2200);

        // this.d_skyCube = new THREE.Mesh( geometry, d_material );
        this.n_skyCube = new THREE.Mesh(geometry, n_material);
        this.scene.background = d_textureCube;
        // this.scene.add(this.d_skyCube);
        this.scene.add(this.n_skyCube);

    }
    initCamera() {
        var width = this.container.offsetWidth; //窗口文档显示区的宽度
        var height = this.container.offsetHeight; //窗口文档显示区的高度

        var k = width / height; //Three.js输出的Cnavas画布宽高比
        this.camera = new THREE.PerspectiveCamera(60, k, 1, 30000);
        this.camera.position.set(12.59, 54.61, 163.8);
    }


    initLight() {
        /**
        * 光源设置
        */
        // 平行光1
        var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(400, 200, 300);
        this.lightGroup.add(directionalLight);
        // 平行光2
        var directionalLight2 = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight2.position.set(-400, -200, -300);
        this.lightGroup.add(directionalLight2);
        //环境光
        this.AmbientLight = new THREE.AmbientLight(0xffffff, 1);
        this.scene.add(this.AmbientLight);

    }
    initRenderer() {

        var width = this.container.offsetWidth; //窗口文档显示区的宽度
        var height = this.container.offsetHeight; //窗口文档显示区的高度

        this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        // 设置屏幕像素比
        this.renderer.setPixelRatio(window.devicePixelRatio);
        // 渲染的尺寸大小
        this.renderer.setSize(width, height);
        this.container.appendChild(this.renderer.domElement);
    }

    inittag() {

        this.tag = new CSS2DObject(this.tagDom);
        this.scene.add(this.tag);
    }

    iniLabelRenderer() {
        var width = this.container.offsetWidth; //窗口文档显示区的宽度
        var height = this.container.offsetHeight; //窗口文档显示区的高

        this.labelRenderer = new CSS2DRenderer();
        this.labelRenderer.setSize(width, height);
        this.labelRenderer.domElement.style.position = 'absolute';
        // 相对鼠标单击位置偏移
        this.labelRenderer.domElement.style.top = '-130px';
        this.labelRenderer.domElement.style.left = '0px';
        // //设置.pointerEvents=none，以免模型标签HTML元素遮挡鼠标选择场景模型
        this.labelRenderer.domElement.style.pointerEvents = 'none';
        this.container.appendChild(this.labelRenderer.domElement);

    }
    render() {
        var delta = this.clock.getDelta();
        this.controls.update(delta);
        this.renderer.render(this.scene, this.camera);
        this.labelRenderer.render(this.scene, this.camera);
    }

    animate() {
        this.renderer.setAnimationLoop(this.render.bind(this));
    }
    initControls() {
        this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        // 使动画循环使用时阻尼或自转 意思是否有惯性
        this.controls.enableDamping = true;
        //动态阻尼系数 就是鼠标拖拽旋转灵敏度
        //controls.dampingFactor = 0.25;
        this.controls.enableZoom = true;
        // this.controls.minDistance = 200;
        this.controls.maxDistance = 600;
        this.controls.autoRotate = false;
        this.controls.enablePan = true;
        this.controls.maxPolarAngle = Math.PI / 2 - 0.05;

    }
    onWindowResize() {
        var width = this.container.offsetWidth; //窗口文档显示区的宽度
        var height = this.container.offsetHeight; //窗口文档显示区的高
        this.camera.aspect = width / height;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(width, height);
        this.labelRenderer.setSize(width, height);
        // this.render();
    }



    chooseClick(event) {
        console.log(this.camera.position);

        var Sx = event.clientX; //鼠标单击位置横坐标
        var Sy = event.clientY; //鼠标单击位置纵坐标

        //屏幕坐标转WebGL标准设备坐标
        var width = this.container.offsetWidth; //窗口文档显示区的宽度
        var height = this.container.offsetHeight; //窗口文档显示区的高

        var x = (Sx / width) * 2 - 1; //WebGL标准设备横坐标
        var y = -(Sy / height) * 2 + 1; //WebGL标准设备纵坐标

        var raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(new THREE.Vector2(x, y), this.camera);
        var intersects = raycaster.intersectObjects(this.hots, true);
        if (intersects.length > 0) {
            var object = intersects[0].object;
            console.log(object);
            // if (object.uType == "video") {
            //     var data = {
            //         title: object.name,
            //         videoUrl: object.videoUrl
            //     }
            //     emitter.emit(ThreeSceneEvent.videoPlay, data);
            // }
            if (object.uType == "video2") {
                var data = {
                    title: object.name,
                    videoUrl: object.videoUrl
                }
                emitter.emit(ThreeSceneEvent.videoPlay2, data);
            }
        }
    }
    chooseMove(event) {

        var Sx = event.clientX; //鼠标单击位置横坐标
        var Sy = event.clientY; //鼠标单击位置纵坐标

        //屏幕坐标转WebGL标准设备坐标
        var width = this.container.offsetWidth; //窗口文档显示区的宽度
        var height = this.container.offsetHeight; //窗口文档显示区的高

        var x = (Sx / width) * 2 - 1; //WebGL标准设备横坐标
        var y = -(Sy / height) * 2 + 1; //WebGL标准设备纵坐标

        var raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(new THREE.Vector2(x, y), this.camera);
        var intersects = raycaster.intersectObjects(this.hots, true);
        if (intersects.length > 0) {
            var object = intersects[0].object;
            // console.log(object);
            if (object.uType == "msgInfo") {
                var point = intersects[0].point;
                this.tag.position.copy(point);
                this.tag.element.style.visibility = "visible";
                var data = {
                    status: true,
                }
                emitter.emit(ThreeSceneEvent.msgInfoTag, data);
            } else {
                this.tag.element.style.visibility = "hidden";
                // var  data = {
                //     status:false,
                // }
                // emitter.emit(ThreeSceneEvent.msgInfoTag,data);

            }
        } else {
            this.tag.element.style.visibility = "hidden";
            // var  data = {
            //     status:false,
            // }
            // emitter.emit(ThreeSceneEvent.msgInfoTag,data);
        }
    }

    addMesh() {
        console.log("添加mesh");
        let _self = this;
        const loader = new GLTFLoader();

        _self.scene.add(_self.lightGroup);
        loader.load(
            _self.modelUrl,
            function (gltf) {
                _self.scene.add(gltf.scene);


                // 对应增加点光源
                gltf.scene.traverse(child => {
                    if (child.name.indexOf("Light") >= 0) {
                        var p = child.position;
                        const light = new THREE.PointLight(0xffffff, 0, 10);
                        light.position.copy(p);
                        _self.lightGroup.add(light);

                        // const sphereSize = 1;
                        // const pointLightHelper = new THREE.PointLightHelper( light, sphereSize );
                        // _self.lightGroup.add( pointLightHelper );
                    }
                })


                console.log(gltf);
            },
            function (xhr) {
                console.log((xhr.loaded / xhr.total * 100) + '% loaded');
            },
            function (error) {
                console.log('An error happened');
            }
        );
    }
    changeWeather(status) {
        let _self = this;
        switch (status) {
            case "day":
                if (_self.AmbientLight.intensity == 1) return;
                TweenMaxTo(_self.AmbientLight, { intensity: 1 }, 2, 0, () => {
                    _self.n_skyCube.material.opacity = 1 - _self.AmbientLight.intensity;

                    _self.lightGroup.traverse(child => {
                        if (child.type == "PointLight") {
                            child.intensity = 1 - _self.AmbientLight.intensity;
                        } else if (child.type == "DirectionalLight") {
                            child.intensity = _self.AmbientLight.intensity;
                        }
                    })
                }, () => { });
                break;
            case "night":
                if (_self.AmbientLight.intensity == 0.2) return;
                TweenMaxTo(_self.AmbientLight, { intensity: 0.2 }, 2, 0, () => {
                    _self.n_skyCube.material.opacity = 1 - _self.AmbientLight.intensity;
                    _self.lightGroup.traverse(child => {
                        if (child.type == "PointLight") {
                            child.intensity = 1 - _self.AmbientLight.intensity;
                        } else if (child.type == "DirectionalLight") {
                            child.intensity = _self.AmbientLight.intensity;
                        }
                    })
                }, () => { });
                break;
        }
    }

    createHot() {

        // https://jvlihd.oss-cn-shenzhen.aliyuncs.com/video/video11.mp4
        this.iconGroup = new THREE.Group();
        console.log("创建热点");
        var arr = [
            {
                name: "仓库1_1号机位", mapUrl: "./images/park.png", color: "rgb(200,60,20)", type: "video2",
                pos: { x: 50, y: 15, z: 0 }, videoUrl: "http://116.131.22.58:11000/sms/34020000002020000001/flv/hls/34020000001320000229_34020000001320000229.flv"
            },
            {
                name: "仓库1_2号机位", mapUrl: "./images/hotel.png", color: "rgb(20,200,20)", type: "msgInfo",
                pos: { x: -23.624, y: 15, z: 29.024 }
            },
            {
                name: "仓库1_2号机位", mapUrl: "./images/hotel.png", color: "rgb(20,200,20)", type: "msgInfo",
                pos: { x: -45.837, y: 15, z: -75.677 }
            },
        ];
        var textureLoader = new THREE.TextureLoader();

        arr.forEach(el => {
            var map = textureLoader.load(el.mapUrl);
            var color = el.color;
            var SpriteMaterial = new THREE.SpriteMaterial({ map: map, transparent: true, color: color, depthTest: false });
            var Sprite = new THREE.Sprite(SpriteMaterial);
            Sprite.position.set(el.pos.x, el.pos.y, el.pos.z);
            Sprite.scale.set(5, 5, 1);
            Sprite.name = "posIcon_" + el.name;
            Sprite.uType = el.type;
            if (el.videoUrl) {
                Sprite.videoUrl = el.videoUrl;

            }
            this.hots.push(Sprite);
            this.iconGroup.add(Sprite);
        })


        this.scene.add(this.iconGroup);

    }

    cameraToTarget(status) {
        // 摄像机动画;
        // Vector3 {x: -4.781062759495013, y: 4.263120606495776, z: 72.13671522392877, isVector3: true}

        let _self = this;
        var cameraPos = {};
        var target = {};

        if (status) {
            cameraPos = { x: -4.78, y: 4.26, z: 72.13 };
            target = { x: -13.603, y: 3.216, z: 25.445 };
        } else {
            cameraPos = { x: 12.59, y: 54.61, z: 163.8 };
            target = { x: 0, y: 0, z: 0 };
        }

        var data1 = {
            t_x: _self.controls.target.x,
            t_y: _self.controls.target.y,
            t_z: _self.controls.target.z,
            c_x: _self.camera.position.x,
            c_y: _self.camera.position.y,
            c_z: _self.camera.position.z,
        }

        var data2 = {
            t_x: target.x,
            t_y: target.y,
            t_z: target.z,
            c_x: cameraPos.x,
            c_y: cameraPos.y,
            c_z: cameraPos.z,
        }

        function update() {
            _self.camera.position.set(data1.c_x, data1.c_y, data1.c_z);
            _self.controls.target.set(data1.t_x, data1.t_y, data1.t_z);
        }

        function calback() {

            // console.log(config.cameraTargetStack );
        }

        TweenMaxTo(data1, data2, 1, 0, update, calback);
    }

}


export default Base3D;
